/*=============================================================================

  Library: HMPBundleFrame

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

=============================================================================*/

#include "Bundle_p.h"
#include "BundleConstants.h"
#include "BundleDatabaseException.h"
#include "BundleArchive_p.h"
#include "BundleFrameworkContext_p.h"
#include "BundleFrameworkUtil_p.h"
#include "IBundleActivator.h"
#include "BundleContext_p.h"

#include "ServiceReference_p.h"
#include "IServiceRegistration.h"
#include "Services_p.h"

// for HMP::msecsTo() - remove after switching to Qt 4.7
#include <Utils.h>

#include <typeinfo>

const IBundle::States BundlePrivate::RESOLVED_FLAGS = IBundle::RESOLVED | IBundle::STARTING | IBundle::ACTIVE | IBundle::STOPPING;

//----------------------------------------------------------------------------
void BundlePrivate::LockObject::lock()
{
  m_Lock.lock();
}

//----------------------------------------------------------------------------
bool BundlePrivate::LockObject::tryLock()
{
  return m_Lock.tryLock();
}

//----------------------------------------------------------------------------
bool BundlePrivate::LockObject::tryLock(int timeout)
{
  return m_Lock.tryLock(timeout);
}

//----------------------------------------------------------------------------
void BundlePrivate::LockObject::unlock()
{
  m_Lock.unlock();
}

//----------------------------------------------------------------------------
bool BundlePrivate::LockObject::wait(unsigned long time)
{
  return m_Condition.wait(&m_Lock, time);
}

//----------------------------------------------------------------------------
void BundlePrivate::LockObject::wakeAll()
{
  m_Condition.wakeAll();
}

//----------------------------------------------------------------------------
void BundlePrivate::LockObject::wakeOne()
{
  m_Condition.wakeOne();
}

//----------------------------------------------------------------------------
BundlePrivate::BundlePrivate(
    QWeakPointer<IBundle> qq,
    BundleFrameworkContext* fw,
    QSharedPointer<BundleArchive> pa)
      : q_ptr(qq), fwCtx(fw), id(pa->getPluginId()),
      location(pa->getPluginLocation().toString()), state(IBundle::INSTALLED),
      archive(pa), pluginContext(0), pluginActivator(0), pluginLoader(pa->getLibLocation()),
      resolveFailException(0), eagerActivation(false), wasStarted(false)
{
  //TODO
  //checkCertificates(pa);

  // Get library load hints
  if (fw->props.contains(BundleConstants::FRAMEWORK_PLUGIN_LOAD_HINTS))
  {
    QVariant loadHintsVariant = fw->props[BundleConstants::FRAMEWORK_PLUGIN_LOAD_HINTS];
    if (loadHintsVariant.isValid())
    {
      QLibrary::LoadHints loadHints = loadHintsVariant.value<QLibrary::LoadHints>();
      pluginLoader.setLoadHints(loadHints);
    }
  }

  checkManifestHeaders();

  pluginDir = fwCtx->getDataStorage(id);
//  int oldStartLevel = archive->getStartLevel();
  try
  {
    //TODO: StartLevel Service
    //if (fwCtx->startLevelController == 0)
    //{
      archive->setStartLevel(0);
    //}
//    else
//    {
//      if (oldStartLevel == -1)
//      {
//        archive->setStartLevel(fwCtx->startLevelController->getInitialPluginStartLevel());
//      }
//    }
  }
  catch (const std::exception& e)
  {
    qDebug() << "Failed to set start level on #" << id << ":" << e.what();
  }

  lastModified = archive->getLastModified();
  if (lastModified.isNull())
  {
    modified();
  }

  // fill require list
  QString requireString = archive->getAttribute(BundleConstants::REQUIRE_PLUGIN);
  QList<QMap<QString, QStringList> > requireList = PluginFrameworkUtil::parseEntries(BundleConstants::REQUIRE_PLUGIN,
                                                                                        requireString, true, true, false);
  QListIterator<QMap<QString, QStringList> > i(requireList);
  while (i.hasNext())
  {
    const QMap<QString, QStringList>& e = i.next();
    const QStringList& res = e.value(BundleConstants::RESOLUTION_DIRECTIVE);
    const QStringList& version = e.value(BundleConstants::PLUGIN_VERSION_ATTRIBUTE);
    RequirePlugin* rp = new RequirePlugin(this, e.value("$key").front(),
                                                res.empty() ? QString() : res.front(),
                                                version.empty() ? QString() : version.front());
    require.push_back(rp);
  }
}

//----------------------------------------------------------------------------
BundlePrivate::BundlePrivate(QWeakPointer<IBundle> qq,
                                   BundleFrameworkContext* fw,
                                   long id, const QString& loc, const QString& sym, const Version& ver)
                                     : q_ptr(qq), fwCtx(fw), id(id), location(loc), symbolicName(sym), version(ver),
                                       state(IBundle::INSTALLED), archive(0), pluginContext(0),
                                       pluginActivator(0), resolveFailException(0),
                                       eagerActivation(false), wasStarted(false)
{
  modified();
}

//----------------------------------------------------------------------------
BundlePrivate::~BundlePrivate()
{
  qDeleteAll(require);
}

//----------------------------------------------------------------------------
IBundle::State BundlePrivate::getUpdatedState()
{
  if (state & IBundle::INSTALLED)
  {
    Locker sync(&operationLock);
    getUpdatedState_unlocked();
  }
  return state;
}

//----------------------------------------------------------------------------
IBundle::State BundlePrivate::getUpdatedState_unlocked()
{
  if (state & IBundle::INSTALLED)
  {
    try
    {
      if (state == IBundle::INSTALLED)
      {
        operation.fetchAndStoreOrdered(RESOLVING);
        fwCtx->resolvePlugin(this);
        state = IBundle::RESOLVED;
        // TODO plugin threading
        //bundleThread().bundleChanged(new BundleEvent(BundleEvent.RESOLVED, this));
        fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::RESOLVED, this->q_func()));
        operation.fetchAndStoreOrdered(IDLE);
      }
    }
    catch (const BundleException& pe)
    {
      if (resolveFailException) delete resolveFailException;
      resolveFailException = new BundleException(pe);
      this->fwCtx->listeners.frameworkError(this->q_func(), pe);
    }
  }
  return state;
}

//----------------------------------------------------------------------------
QFileInfo BundlePrivate::getDataRoot()
{
  return pluginDir;
}

//----------------------------------------------------------------------------
void BundlePrivate::setStateInstalled(bool sendEvent)
{
  Locker sync(&operationLock);

  // Make sure that the context is invalid
  if (pluginContext != 0)
  {
    pluginContext->d_func()->invalidate();
    pluginContext.reset();
  }
  state = IBundle::INSTALLED;
  if (sendEvent)
  {
    operation.fetchAndStoreOrdered(UNRESOLVING);
    // TODO: plugin thread
    //bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this));
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::UNRESOLVED, this->q_func()));
  }
  operation.fetchAndStoreOrdered(IDLE);
}

//----------------------------------------------------------------------------
void BundlePrivate::purge()
{
  if (state == IBundle::UNINSTALLED)
  {
    fwCtx->plugins->remove(location);
  }
//  Vector fix = oldGenerations;
//  if (fix != null) {
//    oldGenerations = null;
//    for (Iterator i = fix.iterator(); i.hasNext();) {
//      ((BundleGeneration)i.next()).purge(true);
//    }
//  }
}

//----------------------------------------------------------------------------
void BundlePrivate::setAutostartSetting(const IBundle::StartOptions& setting) {
  try
  {
    if (archive)
    {
      archive->setAutostartSetting(setting);
    }
  }
  catch (const PluginDatabaseException& e)
  {
    this->fwCtx->listeners.frameworkError(this->q_func(), e);
  }
}

//----------------------------------------------------------------------------
void BundlePrivate::ignoreAutostartSetting()
{
  try
  {
    if (archive)
    {
      archive->setAutostartSetting(-1);
    }
  }
  catch (const PluginDatabaseException& e)
  {
    this->fwCtx->listeners.frameworkError(this->q_func(), e);
  }
}

//----------------------------------------------------------------------------
void BundlePrivate::modified()
{
  lastModified = QDateTime::currentDateTime();
  if (archive)
  {
    archive->setLastModified(lastModified);
  }
}

//----------------------------------------------------------------------------
void BundlePrivate::checkManifestHeaders()
{
  symbolicName = archive->getAttribute(BundleConstants::PLUGIN_SYMBOLICNAME);

  if (symbolicName.isEmpty())
  {
    throw InvalidArgumentException(QString("Bundle has no symbolic name, location=") +
                                      location);
  }

  QString mpv = archive->getAttribute(BundleConstants::PLUGIN_VERSION);
  if (!mpv.isEmpty())
  {
    try
    {
      version = Version(mpv);
    }
    catch (const std::exception& e)
    {
      throw InvalidArgumentException(QString("Bundle does not specify a valid ") +
                                        BundleConstants::PLUGIN_VERSION + " header. Got exception: " + e.what());
    }
  }

  QSharedPointer<IBundle> snp = fwCtx->plugins->getPlugin(symbolicName, version);
  // TBD! Should we allow update to same version?
  if (!snp.isNull() && snp->d_func() != this)
  {
    throw InvalidArgumentException(QString("Bundle with same symbolic name and version is already installed (")
                                      + symbolicName + ", " + version.toString() + ")");
  }

  QString ap = archive->getAttribute(BundleConstants::PLUGIN_ACTIVATIONPOLICY);
  if (BundleConstants::ACTIVATION_EAGER == ap)
  {
    eagerActivation = true;
  }

}

//----------------------------------------------------------------------------
void BundlePrivate::finalizeActivation()
{
  Locker sync(&operationLock);

  // 4: Resolve plugin (if needed)
  switch (getUpdatedState_unlocked())
  {
  case IBundle::INSTALLED:
    Q_ASSERT_X(resolveFailException != 0, Q_FUNC_INFO, "no resolveFailException");
    throw BundleException(*resolveFailException);
  case IBundle::STARTING:
    if (operation.fetchAndAddOrdered(0) == ACTIVATING) return; // finalization already in progress.
    // Lazy activation; fall through to RESOLVED.
  case IBundle::RESOLVED:
  {
    //6:
    state = IBundle::STARTING;
    operation.fetchAndStoreOrdered(ACTIVATING);
    if (fwCtx->debug.lazy_activation)
    {
      qDebug() << "activating #" << this->id;
    }
    //7:
    if (!pluginContext)
    {
      pluginContext.reset(new IBundleContext(this));
    }
    // start dependencies
    startDependencies();
    //TODO plugin threading
    //RuntimeException* e = bundleThread().callStart0(this);
    RuntimeException* e = start0();
    operation.fetchAndStoreOrdered(IDLE);
    operationLock.wakeAll();
    if (e)
    {
      RuntimeException re(*e);
      delete e;
      throw re;
    }
    break;
  }
  case IBundle::ACTIVE:
    break;
  case IBundle::STOPPING:
    // This happens if start is called from inside the BundleActivator::stop method.
    // Don't allow it.
    throw BundleException("start called from BundleActivator::stop",
                             BundleException::ACTIVATOR_ERROR);
  case IBundle::UNINSTALLED:
    throw IllegalStateException("Bundle is in UNINSTALLED state");
  }
}

//----------------------------------------------------------------------------
const RuntimeException* BundlePrivate::stop0()
{
  wasStarted = state == IBundle::ACTIVE;
  // 5:
  state = IBundle::STOPPING;
  operation.fetchAndStoreOrdered(DEACTIVATING);
  // 6-13:
  // TODO plugin threading
  //const RuntimeException* savedException = pluginThread().callStop1(this);
  const RuntimeException* savedException = stop1();
  if (state != IBundle::UNINSTALLED)
  {
    state = IBundle::RESOLVED;
    // TODO plugin threading
    //bundleThread().bundleChanged(new BundleEvent(BundleEvent.STOPPED, this));
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STOPPED, this->q_func()));

    operationLock.wakeAll();
    operation.fetchAndStoreOrdered(IDLE);
  }
  return savedException;
}

//----------------------------------------------------------------------------
const RuntimeException* BundlePrivate::stop1()
{
  const RuntimeException* res = 0;

  //6:
  fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STOPPING, q_func()));

  //7:
  if (wasStarted && pluginActivator)
  {
    try
    {
      pluginActivator->stop(pluginContext.data());
      if (state != IBundle::STOPPING)
      {
        if (state == IBundle::UNINSTALLED)
        {
          return new IllegalStateException("Plug-in is uninstalled");
        }
        else
        {
          return new IllegalStateException("Plug-in changed state because of refresh during stop");
        }
      }
    }
    catch (const Exception& e)
    {
      res = new BundleException("Plugin::stop: BundleActivator stop failed",
                                   BundleException::ACTIVATOR_ERROR, e);
    }
    catch (...)
    {
      res = new BundleException("Plugin::stop: BundleActivator stop failed",
                                   BundleException::ACTIVATOR_ERROR);
    }
    pluginActivator = 0;
  }

  if (operation.fetchAndAddOrdered(0) == DEACTIVATING)
  {
    // Call hooks after we've called BundleActivator::stop(), but before we've
    // cleared all resources
    if (pluginContext)
    {
      // TODO service listener hooks
      //fwCtx->listeners.serviceListeners.hooksBundleStopped(this);

      //8-10:
      removePluginResources();
	  if (pluginContext)
		pluginContext->d_func()->invalidate();
      pluginContext.reset();
    }
  }

  // This would unload the shared library and delete the activator if
  // there are no dependencies. However, objects from the plug-in might
  // have been created via C-function symbol lookups. Hence we cannot
  // safely unload the DLL. Maybe implement a in-DLL counter later
  // (http://stackoverflow.com/questions/460809/c-dll-unloading-issue and
  // http://boost.2283326.n4.nabble.com/shared-ptr-A-smarter-smart-pointer-proposal-for-dynamic-libraries-td2649749.html).
  // The activator itself will be delete during program termination
  // (by the QPluginLoader instance).
  //pluginLoader.unload();

  return res;
}

//----------------------------------------------------------------------------
void BundlePrivate::update0(const QUrl& updateLocation, bool wasActive)
{
  const bool wasResolved = state == IBundle::RESOLVED;
  const int oldStartLevel = getStartLevel();
  QSharedPointer<BundleArchive> newArchive;

  operation.fetchAndStoreOrdered(UPDATING);
  try
  {
    // New plugin as stream supplied?
    QUrl updateUrl(updateLocation);
    if (updateUrl.isEmpty())
    {
      // Try Bundle-UpdateLocation
      QString update = archive != 0 ? archive->getAttribute(BundleConstants::PLUGIN_UPDATELOCATION) : QString();
      if (update.isEmpty())
      {
        // Take original location
        updateUrl = location;
      }
    }

    if(updateUrl.scheme() != "file")
    {
      QString msg = "Unsupported update URL:";
      msg += updateUrl.toString();
      throw BundleException(msg);
    }

    newArchive = fwCtx->storage->updatePluginArchive(archive, updateUrl, updateUrl.toLocalFile());
    //checkCertificates(newArchive);
    checkManifestHeaders();
    newArchive->setStartLevel(oldStartLevel);
    fwCtx->storage->replacePluginArchive(archive, newArchive);
  }
  catch (const std::exception& e)
  {
    if (!newArchive.isNull())
    {
      newArchive->purge();
    }
    operation.fetchAndStoreOrdered(IDLE);
    if (wasActive)
    {
      try
      {
        this->q_func().data()->start();
      }
      catch (const BundleException& pe)
      {
        fwCtx->listeners.frameworkError(this->q_func(), pe);
      }
    }
    try
    {
      const BundleException& pe = dynamic_cast<const BundleException&>(e);
      throw pe;
    }
    catch (std::bad_cast)
    {
      throw BundleException(QString("Failed to get update plugin: ") + e.what(),
                               BundleException::UNSPECIFIED);
    }
  }

  bool purgeOld = false;
  // TODO: check if dependent plug-ins are started. If not, set purgeOld to true.

  // Activate new plug-in
  QSharedPointer<BundleArchive> oldArchive = archive;
  archive = newArchive;
  cachedRawHeaders.clear();
  state = IBundle::INSTALLED;

  // Purge old archive
  if (purgeOld)
  {
    //secure.purge(this, oldProtectionDomain);
    if (oldArchive != 0)
    {
      oldArchive->purge();
    }
  }

  // Broadcast events
  if (wasResolved)
  {
    // TODO: use plugin threading
    //bundleThread().bundleChanged(new BundleEvent(BundleEvent.UNRESOLVED, this));
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::UNRESOLVED, this->q_func()));
  }
  //bundleThread().bundleChanged(new BundleEvent(BundleEvent.UPDATED, this));
  fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::UPDATED, this->q_func()));
  operation.fetchAndStoreOrdered(IDLE);

   // Restart plugin previously stopped in the operation
   if (wasActive)
   {
     try
     {
       this->q_func().data()->start();
     }
     catch (const BundleException& pe)
     {
       fwCtx->listeners.frameworkError(this->q_func(), pe);
     }
   }
 }

//----------------------------------------------------------------------------
int BundlePrivate::getStartLevel()
{
  if (archive != 0)
  {
    return archive->getStartLevel();
  }
  else
  {
    return 0;
  }
}

//----------------------------------------------------------------------------
void BundlePrivate::waitOnOperation(LockObject* lock, const QString& src, bool longWait)
{
  if (operation.fetchAndAddOrdered(0) != IDLE)
  {
    qint64 left = longWait ? 20000 : 500;
    QDateTime waitUntil = QDateTime::currentDateTime().addMSecs(left);
    do
    {
      lock->wait(left);
      if (operation.fetchAndAddOrdered(0) == IDLE)
      {
        return;
      }
      // TODO use Qt 4.7 QDateTime::msecsTo() API
      //left = QDateTime::currentDateTime().msecsTo(waitUntil);
      left = HMP::msecsTo(QDateTime::currentDateTime(), waitUntil);
    } while (left > 0);

    QString op;
    switch (operation.fetchAndAddOrdered(0))
    {
    case IDLE:
      // Should not happen!
      return;
    case ACTIVATING:
      op = "start";
      break;
    case DEACTIVATING:
      op = "stop";
      break;
    case RESOLVING:
      op = "resolve";
      break;
    case UNINSTALLING:
      op = "uninstall";
      break;
    case UNRESOLVING:
      op = "unresolve";
      break;
    case UPDATING:
      op = "update";
      break;
    default:
      op = "unknown operation";
      break;
    }
    throw BundleException(src + " called during " + op + " of plug-in",
                             BundleException::STATECHANGE_ERROR);
  }
}

//----------------------------------------------------------------------------
QStringList BundlePrivate::findResourceEntries(const QString& path,
                                                  const QString& pattern, bool recurse) const
{
  QStringList result;
  QStringList resources = archive->findResourcesPath(path);
  foreach(QString fp, resources)
  {
    QString lastComponentOfPath = fp.section('/', -1);
    bool isDirectory = fp.endsWith("/");

    if (!isDirectory &&
        (pattern.isNull() || PluginFrameworkUtil::filterMatch(pattern, lastComponentOfPath)))
    {
      result << (path + fp);
    }
    if (isDirectory && recurse)
    {
      QStringList subResources = findResourceEntries(fp, pattern, recurse);
      foreach (QString subResource, subResources)
      {
        result << (path + subResource);
      }
    }
  }
  return result;
}

//----------------------------------------------------------------------------
void BundlePrivate::startDependencies()
{
  QListIterator<RequirePlugin*> i(this->require);
  while (i.hasNext())
  {
    RequirePlugin* pr = i.next();
    QList<IBundle*> pl = fwCtx->plugins->getPlugins(pr->name, pr->pluginRange);
    if (pl.isEmpty())
    {
      if (pr->resolution == BundleConstants::RESOLUTION_MANDATORY)
      {
        // We should never get here, since the plugin can only be
        // started if all its dependencies could be resolved.
        throw BundleException(
            QString("Internal error: dependent plugin %1 inside version range %2 is not installed.").
            arg(pr->name).arg(pr->pluginRange.toString()));
      }
      else
      {
        continue;
      }
    }

    // We take the first plugin in the list (highest version number)
    // Immediately start the dependencies (no lazy activation) but do not
    // change the autostart setting of the plugin.
    pl.front()->start(IBundle::START_TRANSIENT);
  }
}

//----------------------------------------------------------------------------
BundleException* BundlePrivate::start0()
{
  BundleException* res = 0;

  fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STARTING, this->q_func()));

  BundleException::Type error_type = BundleException::MANIFEST_ERROR;
  try {
    pluginLoader.load();
    if (!pluginLoader.isLoaded())
    {
      error_type = BundleException::ACTIVATOR_ERROR;
      throw BundleException(QString("Loading plugin %1 failed: %2").arg(pluginLoader.fileName()).arg(pluginLoader.errorString()),
                               BundleException::ACTIVATOR_ERROR);
    }

    pluginActivator = qobject_cast<IBundleActivator*>(pluginLoader.instance());
    if (!pluginActivator)
    {
      throw BundleException(QString("Creating BundleActivator instance from %1 failed: %2").arg(pluginLoader.fileName()).arg(pluginLoader.errorString()),
                               BundleException::ACTIVATOR_ERROR);
    }

    pluginActivator->start(pluginContext.data());

    if (state != IBundle::STARTING)
    {
      error_type = BundleException::STATECHANGE_ERROR;
      if (IBundle::UNINSTALLED == state)
      {
        throw BundleException("Plugin uninstalled during start()", BundleException::STATECHANGE_ERROR);
      }
      else
      {
        throw BundleException("Plugin changed state because of refresh during start()", BundleException::STATECHANGE_ERROR);
      }
    }
    state = IBundle::ACTIVE;
  }
  catch (const Exception& e)
  {
    res = new BundleException("Plugin start failed", error_type, e);
  }
  catch (...)
  {
    res = new BundleException("Plugin start failed", error_type);
  }

  if (fwCtx->debug.lazy_activation)
  {
    qDebug() << "activating #" << id << "completed.";
  }

  if (res == 0)
  {
    //10:
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STARTED, this->q_func()));
  }
  else if (operation.fetchAndAddOrdered(0) == ACTIVATING)
  {
    // 8:
    state = IBundle::STOPPING;
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STOPPING, this->q_func()));
    removePluginResources();
    pluginContext->d_func()->invalidate();
    pluginContext.reset();
    state = IBundle::RESOLVED;
    fwCtx->listeners.emitPluginChanged(BundleEvent(BundleEvent::STOPPED, this->q_func()));
  }

  return res;
}

//----------------------------------------------------------------------------
void BundlePrivate::removePluginResources()
{
  // automatic disconnect due to Qt signal slot
  //fwCtx->listeners.removeAllListeners(this);

  QList<IServiceRegistration> srs = fwCtx->services->getRegisteredByPlugin(this);
  QMutableListIterator<IServiceRegistration> i(srs);
  while (i.hasNext())
  {
    try
    {
      i.next().unregister();
    }
    catch (const IllegalStateException& /*ignore*/)
    {
      // Someone has unregistered the service after stop completed.
      // This should not occur, but we don't want get stuck in
      // an illegal state so we catch it.
    }
  }

  QList<IServiceRegistration> s = fwCtx->services->getUsedByPlugin(q_func());
  QListIterator<IServiceRegistration> i2(s);
  while (i2.hasNext())
  {
    i2.next().getServiceReference().d_func()->ungetService(q_func(), false);
  }

}

void BundlePrivate::getRegisteredServices(std::vector<IServiceReference> &services)
{
    QList<IServiceRegistration> s = fwCtx->services->getUsedByPlugin(q_func());
    QListIterator<IServiceRegistration> i2(s);
    while (i2.hasNext())
    {
       services.push_back( i2.next().getServiceReference() ) ;
    }

}
